home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 May: Tool Chest / Developer CD Series May 1996 (Tool Chest) (Apple Computer) (1996).iso / Tool Chest / Devices / Apple Desktop Bus / ADB Key Spy 2 / ADBKS Extension.c < prev    next >
Encoding:
Text File  |  1996-01-11  |  9.8 KB  |  435 lines  |  [TEXT/R*ch]

  1.     //
  2.     //    from 'ADB Key Spy' • Pete Gontier • gurgle@apple.com
  3.     //    Macintosh Developer Technical Support
  4.     //    © 1995,1996 Apple Computer, Inc.
  5.     //
  6.     //    Changes:
  7.     //
  8.     //        when        who        what
  9.     //        --------------------------------------------------------------
  10.     //        01/11/96    PG        copied from another project,
  11.     //                            merged with various parts of old
  12.     //                            ADB Key Spy
  13.     //
  14.  
  15. #ifndef __DEVICES__
  16. #    include <Devices.h>
  17. #endif
  18.  
  19. #ifndef __RESOURCES__
  20. #    include <Resources.h>
  21. #endif
  22.  
  23. #ifndef __MEMORY__
  24. #    include <Memory.h>
  25. #endif
  26.  
  27. #ifndef __LOWMEM__
  28. #    include <LowMem.h>
  29. #endif
  30.  
  31. #ifndef __A4STUFF__
  32. #    include <A4Stuff.h>
  33. #endif
  34.  
  35. #include "ADBKS Common.h"
  36. #include "ADBKS csCodes.h"
  37.  
  38.     //
  39.     //    vKeyboardServiceRoutineAsm
  40.     //
  41.     //    This is a declaration for a function which is in fact
  42.     //    never called from C but only by ADB and consists of 68K
  43.     //    assembly. However, I pass the thing around enough that
  44.     //    it was convenient to define a type for it.
  45.     //
  46.  
  47. typedef asm void (vKeyboardServiceRoutineAsm) (void);
  48.  
  49.     //
  50.     //    dCtlFlags
  51.     //
  52.     //    These are the device control entry flags for the driver.
  53.     //    Compiler doesn't allow me to specify them with quite enough
  54.     //    flexibility (i.e. none), and I don't want to put a manual
  55.     //    resource edit into the build process, so I have code do it.
  56.     //
  57.  
  58. const short dCtlFlags = dRAMBasedMask | dCtlEnableMask | dStatEnableMask;
  59.  
  60. enum
  61. {
  62.     //
  63.     //    Some miscellaneous quantities needed for installing a driver
  64.     //    into the unit table which for whatever reason do not
  65.     //    appear in <Devices.h>.
  66.     //
  67.  
  68.     kMaxUTEntries    = 128,    // maximum size of unit table
  69.     kMinUnitNum        = 48    // lowest unit number we can use
  70. };
  71.  
  72. static pascal OSErr GrowUnitTable (void)
  73. {
  74.     //
  75.     //    Called when there are no unused slots in unit table.
  76.     //    Expands table by 4 entries.
  77.     //
  78.  
  79.     OSErr    err                    = noErr;
  80.     short    oldUnitEntryCount    = LMGetUnitTableEntryCount ( );
  81.     short    newUnitEntryCount;
  82.     
  83.     if (oldUnitEntryCount < kMinUnitNum)
  84.         newUnitEntryCount = 64;
  85.     else
  86.         newUnitEntryCount = oldUnitEntryCount + 4;
  87.     
  88.     if (newUnitEntryCount > kMaxUTEntries)
  89.         err = unitTblFullErr;
  90.     else
  91.     {
  92.         Ptr newUnitTableBase = NewPtrSysClear (newUnitEntryCount * sizeof(long));
  93.         if (!(err = MemError ( )))
  94.         {
  95.             Ptr oldUnitTableBase = LMGetUTableBase ( );
  96.  
  97.             BlockMove (oldUnitTableBase, newUnitTableBase, oldUnitEntryCount * 4);
  98.             LMSetUTableBase (newUnitTableBase);
  99.             LMSetUnitTableEntryCount (newUnitEntryCount);
  100.             DisposePtr (oldUnitTableBase);
  101.         }
  102.     }
  103.     
  104.     return err;
  105. }
  106.  
  107. static pascal OSErr DriverInstall (Handle drvrHandle, short drvrRefNum)
  108. {
  109.     //
  110.     //    Creates a DCtlHandle and poulates its fields to describe driver to be installed.
  111.     //    Installs new DCtlHandle into unit table.
  112.     //
  113.  
  114.     OSErr err = noErr;
  115.  
  116.     ReserveMem (sizeof (DCtlEntry));
  117.     if (!(err = MemError ( )))
  118.     {
  119.         DCtlHandle dceHandle = (DCtlHandle) NewHandleSysClear (sizeof(DCtlEntry));
  120.         if (!(err = MemError ( )))
  121.         {
  122.             short            unitNum        = -1 * (drvrRefNum + 1);
  123.             DCtlHandle        *unitTable    = (DCtlHandle *) LMGetUTableBase ( );
  124.  
  125.             (**dceHandle).dCtlDriver    = (Ptr) drvrHandle;
  126.             (**dceHandle).dCtlFlags        |= dCtlFlags;
  127.             (**dceHandle).dCtlRefNum    = drvrRefNum;        
  128.     
  129.             unitTable [unitNum] = dceHandle;        
  130.         }
  131.     }
  132.  
  133.     return err;
  134. }
  135.  
  136. static pascal short GetUnusedDrvrRefNum (void)
  137. {
  138.     //
  139.     //    Attempts to obtain an unused driver slot.
  140.     //
  141.  
  142.     DCtlHandle    *unitTable        = (DCtlHandle *) LMGetUTableBase ( );
  143.     short        unitEntryCount    = LMGetUnitTableEntryCount ( );
  144.     short        unitNumber        = kMinUnitNum;
  145.     short        drvrRefNum        = 0;
  146.     
  147.     while (unitTable[unitNumber] && unitNumber < unitEntryCount)
  148.         ++unitNumber;
  149.     if (!unitTable[unitNumber])
  150.         drvrRefNum = -1 * (unitNumber + 1);
  151.     
  152.     return drvrRefNum;
  153. }
  154.  
  155. static pascal OSErr GetDrvrRefNum (short *drvrRefNum)
  156. {
  157.     //
  158.     //    Attempts to obtain an unused driver slot.
  159.     //    If an empty slot cannot be found, attempts to allocate more slots. 
  160.     //
  161.  
  162.     OSErr err = noErr;
  163.  
  164.     if (LMGetUnitTableEntryCount ( ) < kMinUnitNum)
  165.         err = GrowUnitTable ( );
  166.  
  167.     if (!err)
  168.         if (!(*drvrRefNum = GetUnusedDrvrRefNum ( )))
  169.             if (!(err = GrowUnitTable ( )))
  170.                 if (!(*drvrRefNum = GetUnusedDrvrRefNum ( )))
  171.                     err = unitTblFullErr;
  172.  
  173.     return err;
  174. }
  175.  
  176. static pascal OSErr GetKMAP (tKeyboardInfo *kbInfo, char devType)
  177. {
  178.     //
  179.     //    GetKMAP
  180.     //
  181.     //    The 'KMAP' resources map raw key codes to virtual key codes.
  182.     //    To make it possible for the service routine to easily perform
  183.     //    this mapping, we toss a handle to the appropriate 'KMAP'
  184.     //    resource into each keyboard info record.
  185.     //
  186.     //    The resource is marked locked, so it's interrupt-safe.
  187.     //    The resource is marked system-heap, which is what we want
  188.     //    because we are an INIT and our heap will disappear soon.
  189.     //
  190.     //    One is not supposed to release resources which potentially come from
  191.     //    the System file because they might be shared. Thus, we get our resource
  192.     //    and keep it ("leak" it). If you have 'KMAP' resources in some other file
  193.     //    for some reason, then you might want to call HomeResFile here to help
  194.     //    you decide whether to release the resource.
  195.     //
  196.  
  197.     OSErr err = noErr;
  198.  
  199.     const ResType kmapResType = 'KMAP';
  200.  
  201.     tKeyMapResourceH kmapH = (tKeyMapResourceH) GetResource (kmapResType, devType);
  202.     err = ResError ( );
  203.     if (err == resNotFound || !kmapH)
  204.     {
  205.         kmapH = (tKeyMapResourceH) GetResource (kmapResType, 0);
  206.         err = ResError ( );
  207.         if (err == resNotFound)
  208.         {
  209.             err = noErr;
  210.             kmapH = nil; // just to be sure
  211.         }
  212.     }
  213.  
  214.     kbInfo->keyMapResH = kmapH;
  215.  
  216.     return err;
  217. }
  218.  
  219. static pascal OSErr AcquireKeyboards
  220.     (vKeyboardServiceRoutineAsm *serviceRoutine, tKeyboardInfoP *keyboardInfoList)
  221. {
  222.     //
  223.     //    Walks the ADB device list and patches the service routine
  224.     //    of each keyboard so that an extra (internal) key map is maintained.
  225.     //    A block of memory is allocated via NewPtr for each keyboard.
  226.     //    Blocks are strung together into a list and returned.
  227.     //
  228.  
  229.     OSErr err = noErr;
  230.  
  231.     ADBSetInfoBlock        siBlock;
  232.     ADBDataBlock        adbInfo;
  233.  
  234.     short adbCount = CountADBs ( );
  235.  
  236.     *keyboardInfoList = nil;
  237.  
  238.     while (adbCount)
  239.     {
  240.         ADBAddress adbAddress = GetIndADB (&adbInfo, adbCount);
  241.  
  242.         if (adbAddress < 0)
  243.         {
  244.             DebugStr ("\p adbAddress < 0 ?");
  245.             err = paramErr;
  246.             break;
  247.         }
  248.  
  249.         if (adbInfo.origADBAddr == 2) // 2 == keyboard
  250.         {
  251.             //
  252.             //    allocate a new record to track old service proc addresses
  253.             //
  254.  
  255.             tKeyboardInfo *newKeyboardInfo =
  256.                 (tKeyboardInfo *) NewPtrSysClear (sizeof (tKeyboardInfo));
  257.             err = MemError ( );
  258.             if (err) break;
  259.  
  260.             //
  261.             //    fill in the new record and get ready to insert it into our list
  262.             //
  263.  
  264.             err = GetKMAP (newKeyboardInfo, adbInfo.devType);
  265.             if (err)
  266.             {
  267.                 DisposePtr ((Ptr) newKeyboardInfo);
  268.                 break;
  269.             }
  270.  
  271.             newKeyboardInfo->dbDataAreaAddr        = adbInfo.dbDataAreaAddr;
  272.             newKeyboardInfo->dbServiceRtPtr        = adbInfo.dbServiceRtPtr;
  273.             newKeyboardInfo->next                = *keyboardInfoList;
  274.  
  275.             //
  276.             //    replace the device's service routine and data pointer
  277.             //
  278.     
  279.             siBlock.siService        = (ADBServiceRoutineUPP) serviceRoutine;
  280.             siBlock.siDataAreaAddr    = (Ptr) newKeyboardInfo;
  281.  
  282.             err = SetADBInfo (&siBlock, adbAddress);
  283.             if (err)
  284.             {
  285.                 DisposePtr ((Ptr) newKeyboardInfo);
  286.                 break;
  287.             }
  288.  
  289.             //
  290.             //    insert the new record into our list
  291.             //
  292.  
  293.             *keyboardInfoList = newKeyboardInfo;
  294.         }
  295.  
  296.         --adbCount;
  297.     }
  298.  
  299.     return err;
  300. }
  301.  
  302. static pascal OSErr GetServiceRoutine (vKeyboardServiceRoutineAsm **ksra)
  303. {
  304.     //
  305.     //    Loads and detaches the ADB service routine code resource.
  306.     //    Produces the ADB service routine address.
  307.     //    A copy of the resource stays loaded; call DisposeHandle to free it.
  308.     //
  309.  
  310.     OSErr err = noErr;
  311.  
  312.     //
  313.     //    Assume AKSR 128 is system heap, locked, pre-load.
  314.     //
  315.  
  316.     Handle serviceRoutineH = Get1Resource ('AKSR',128);
  317.  
  318.     *ksra = nil;
  319.  
  320.     if (!(err = ResError ( )))
  321.     {
  322.         DetachResource (serviceRoutineH);
  323.         if (!(err = ResError ( )))
  324.             *ksra = (vKeyboardServiceRoutineAsm *) *serviceRoutineH;
  325.         else
  326.             ReleaseResource (serviceRoutineH);
  327.     }
  328.  
  329.     return err;
  330. }
  331.  
  332. static pascal OSErr AcquireKeyboardsAndLinkToDriver (ConstStr255Param myDriverName)
  333. {
  334.     //
  335.     //    Gets the address of the service routine.
  336.     //    Calls AquireKeyboards to patch all keyboard ADB service routines
  337.     //    and obtain a list of patched keyboard ADB info records.
  338.     //    Tells driver about this list.
  339.     //
  340.  
  341.     short drvrRefNum;
  342.  
  343.     OSErr err = OpenDriver (myDriverName, &drvrRefNum);
  344.  
  345.     if (!err)
  346.     {
  347.         OSErr err2 = noErr;
  348.         vKeyboardServiceRoutineAsm *ksra = nil;
  349.         if (!(err = GetServiceRoutine (&ksra)))
  350.         {
  351.             tKeyboardInfo *keyboardInfoList = nil;
  352.             err = AcquireKeyboards (ksra, &keyboardInfoList);
  353.  
  354.             //
  355.             //    Even if there was an error, there might be a partial list,
  356.             //    so we attempt to install it.
  357.             //
  358.  
  359.             if (keyboardInfoList)
  360.             {
  361.                 err2 = Control (drvrRefNum,kControlCode_SetKeyboardInfoList,&keyboardInfoList);
  362.                 if (!err) err = err2;
  363.             }
  364.         }
  365.     
  366.         //
  367.         //    Close the driver no matter what once it's been opened.
  368.         //    However, don't report errors on close unless nothing else
  369.         //    has gone wrong first.
  370.         //
  371.  
  372.         err2 = CloseDriver (drvrRefNum);
  373.         if (!err) err = err2;
  374.     }
  375.  
  376.     return err;
  377. }
  378.  
  379. static pascal OSErr GetAndInstallMyDriver (ConstStr255Param myDriverName)
  380. {
  381.     //
  382.     //    Makes sure the driver is not already installed.
  383.     //    Loads it and installs it.
  384.     //
  385.  
  386.     short drvrRefNum;
  387.     OSErr err = OpenDriver (myDriverName, &drvrRefNum);
  388.     if (!err)
  389.     {
  390.         CloseDriver (drvrRefNum);
  391.         err = dupFNErr; // best approximation
  392.     }
  393.     else
  394.     {
  395.         Handle driverHandle = Get1Resource ('Drvr', 48);
  396.         if (!(err = ResError ( )) && driverHandle)
  397.         {
  398.             DetachResource (driverHandle);
  399.             err = ResError ( );
  400.             if (err)
  401.                 ReleaseResource (driverHandle);
  402.             else
  403.             {
  404.                 short drvrRefNum = 0;
  405.     
  406.                 **((short **) driverHandle) |= dCtlFlags;
  407.     
  408.                 err = GetDrvrRefNum (&drvrRefNum);
  409.     
  410.                 if (err)
  411.                     DisposeHandle (driverHandle);
  412.                 else
  413.                 {
  414.                     err = DriverInstall (driverHandle, drvrRefNum);
  415.     
  416.                     if (err)
  417.                         DisposeHandle (driverHandle);
  418.                 }
  419.             }
  420.         }
  421.     }
  422.  
  423.     return err;
  424. }
  425.  
  426. void main (void)
  427. {
  428.     long oldA4 = SetCurrentA4 ( );
  429.     const unsigned char *myDriverName = "\p.adb_key_spy";
  430.     OSErr err = GetAndInstallMyDriver (myDriverName);
  431.     if (!err) err = AcquireKeyboardsAndLinkToDriver (myDriverName);
  432.     if (err) SysBeep (10);
  433.     SetA4 (oldA4);
  434. }
  435.